/*
* Fastjs Javascript Frame
*
* About this frame:
*   Version:v1.1.0
*   Author:XiaoDong Team-XiaoDong (xiaodong@indouyin.cn)
*   Contact-Us: xiaodong@indouyin.cn
*   Follow-Us: https://leetcode-cn.com/u/dy_xiaodong/
*              https://juejin.cn/user/3540872450829720/
*
* Frame license:
*   MIT License
*/

/* Fastjs Token ? -- < v1.1.0 > -- ? Fastjs Token */
/* Safety List: ["Vue-Router"] */

const FASTJS_CONFIG = {
    "version": "1.1.0",
    "css": {
        "setup": true,
    },
    "error": {
        "output": {
            "smallErrorOutput": true,
            "errorOutput": true,
            "seriousErrorOutput": true,
            "crashErrorOutput": "always on"
        },
        "other": {
            "outOfRange": true
        }
    },
    "log": {
        "fastjsInstallLog": true,
    },
    "compiler": {
        "qualityInspection": true
    },
    "function": {
        "Class": {
            "dom": {
                "defaultTagName": "div"
            }
        },
        "String": {
            "push": {
                match: "%s%"
            }
        }
    }
}

class dom {
    constructor(tagname, e) {
        // Create new dom
        let el = document.createElement(tagname ? tagname : FASTJS_CONFIG.function.Class.dom.defaultTagName).then(() => {
            if (e && e.length > 1) {
                if (e[0] === '.') this.className = e.substr(1)
                if (e[0] === '#') el.id = e.substr(1)
            }
        })
        // Return htmlDom
        return el
    }
}

var fastjs = {
    setup: () => {
        let log = function () {
            return console.log(this), this
        }
        window.js = fastjs
        let e = {
            addClass(name = "") {
                let el = this
                if (!js.type(name, "string")) {
                    fastjs.throwCrashError("Element.addClass", "name", "type")
                    return void 0
                }
                el.classList.add(name)
                return el
            },
            css(val) {
                if (js.type(val, "string"))
                    this.style = val
                else if (js.type(val, "object"))
                    Object.entries(val).forEach((e) => {
                        this.style[e[0]] = e[1]
                    })
                else this.attr("style", null)
                return this
            },
            insertAfter(el) {
                let par = el.parentNode
                if (par.lastChild === el) par.appendChild(this)
                else par.insertBefore(this, el.nextSibling)
                return this
            },
            attr(e, val = false) {
                if (val === false) return this.getAttribute(e)
                if (val === null) this.removeAttribute(e)
                else this.setAttribute(e, String(val))
                return this
            },
            on(e, func) {
                let val = `on${e}`
                e = func
                if (js.type(e, "function")) {
                    this[val] = () => {
                        e(this)
                    }
                } else if (js.type(e, "string")) {
                    fastjs.qualityOutput("main.on", "We recommend you use function type to give a javascript")
                    this[val] = () => {
                        eval(e)
                    }
                } else {
                    if (!e || e.length === 0) fastjs.qualityOutput("main.on", "Given should not be none")
                    this[val] = () => {
                        e.each((e) => {
                            if (js.type(e, "string")) eval(e)
                            else e(this)
                        })
                    }
                }
                return this
            },
            domAddEnd(el) {
                fastjs.domAddEnd(el, this)
                return this
            },
            html(val) {
                this.innerHTML = val !== undefined ? val : this.innerHTML
                return val === undefined ? this.innerHTML : this
            },
            text(val) {
                this.innerText = val !== undefined ? val : this.innerText
                return val === undefined ? this.innerText : this
            },
            gethtml() {
                return this.html()
            },
            gettext() {
                return this.text()
            },
            next(selecter) {
                return fastjs.dom(selecter, this)
            },
            then(callback) {
                if (js.type(callback, "string")) {
                    eval(callback)
                } else {
                    callback(this)
                }
                return this
            },
            val(text) {
                if (text !== undefined) {
                    this.tagName === "BUTTON" ? this.text(text) : this.value = text
                    return this
                }
                return this.value
            },
            log: log,
            push(selecter) {
                let dom = document.querySelector(selecter)
                if (!dom) {
                    fastjs.throwError("Element.push", "selecter is empty")
                    return this
                }
                dom.appendChild(this)
                return this
            },
            cover(selecter) {
                let dom = document.querySelector(selecter)
                if (!dom) {
                    fastjs.throwError("Element.cover", "selecter is empty")
                    return this
                }
                dom.html().appendChild(this)
                return this
            },
            $: (selecter) => {
                return fastjs.dom(selecter)
            },
            father() {
                return this.parentNode
            }
        }
        Object.entries(e).forEach((e) => {
            Element.prototype[e[0]] = e[1]
        })
        // Fastjs Dom Selecter Setup
        window.$ = fastjs.dom
        e = {
            push($strings, $target) {
                let str = this
                if (!$strings) {
                    $strings = ""
                }
                let mt = FASTJS_CONFIG.function.String.push.match
                if (js.type($strings, "string")) {
                    str = str.replaceAll($target !== void 0 ? $target : mt, $strings)
                } else if (js.type($strings, "object")) {
                    $strings.forEach((e, key) => {
                        if (key >= $strings.length) {
                            e = $strings[$strings.length - 1]
                            if (FASTJS_CONFIG.error.other.outOfRange) {
                                fastjs.throwSmallError("String.push", "List out of range")
                            }
                        }
                        str = str.replace($target !== void 0 ? $target : mt, e)
                    })
                } else {
                    $strings = String($strings)
                    str = str.replaceAll($target !== void 0 ? $target : mt, $strings)
                }
                return str
            },
            search($keyword = "") {
                let str = this.indexOf($keyword)
                return str < 0 ? false : str
            },
            log: log,
            strrev() {
                return this.split("").reverse().join("")
            },
            forEach(callback = () => {
            }) {
                if (!js.type(callback, "function")) {
                    fastjs.throwCrashError("String.forEach", "callback", "type")
                }
                for (let i = 0; i < this.length; i++) {
                    callback(this[i])
                }
            },
            pushToDom(el = "") {
                if (js.type(el, "string") || el == null) {
                    el = document.querySelector(el)
                    if (!el) {
                        fastjs.throwError("String.pushToDom", "selecter is empty")
                        return this
                    }
                }
                el.html(this)
                return this
            },
            array(val) {
                if (js.type(val, "string")) {
                    let str = ""
                    let ar = []
                    for (let i = 0; i < this.length; i++) {
                        str += this[i]
                        if (str.search(val) !== false) {
                            str = str.replace(val, "")
                            ar.push(str)
                            str = ""
                        }
                    }
                    if (str.length) {
                        ar.push(str)
                    }
                    return ar
                } else if (js.type(val, "number")) {
                    let time = 0
                    let str = ""
                    let ar = []
                    for (let i = 0; i < this.length; i++) {
                        time++
                        str += this[i]
                        if (time === val) {
                            ar.push(str)
                            str = ""
                            time = 0
                        }
                    }
                    return ar
                }
                fastjs.throwCrashError("String.array", "val", "type")
                return void 0
            },
            int() {
                return Number(this)
            }
        }
        Object.entries(e).forEach((e) => {
            String.prototype[e[0]] = e[1]
        })
        Number.prototype.str = function (e) {
            return String(this)
        }
        NodeList.prototype.each = function (e) {
            return this.forEach(e), this
        }
        e = {
            search(val) {
                let el = this
                if (js.type(val, "number"))
                    val = String(val)
                else if (!js.type(val, "string")) {
                    fastjs.throwCrashError("Array.search", "val", "type")
                    return void 0
                }
                el = el.indexOf(val) > -1 ? el.indexOf(val) : false
                return el
            },
            random() {
                let upper = this.length - 1
                let lower = 0
                let random = Math.floor(Math.random() * (upper - lower + 1)) + lower
                return this[random]
            },
            add($index, $key) {
                if (!$key && $key !== 0) {
                    this.push($index)
                    return this
                } else {
                    if (this.length < $key || $key < 0) {
                        fastjs.throwCrashError("Array.add", "key is out of range")
                        return void 0
                    }
                }
                this.splice($key, 0, $index)
                return this
            },
            delete($key, $num = 1) {
                if ($num < 1) {
                    fastjs.qualityOutput("Array.delete", "Method calls that could have been ignored")
                    return this
                }
                this.splice($key, $num)
                return this
            },
            resort() {
                return this.sort().reverse()
            },
            string($keyword, $custom) {
                if (!$keyword) {
                    $keyword = ","
                }
                let str = ""
                this.forEach((e, key) => {
                    str += "%s%%s%".push([e, key + 1 === this.length ? "" : $keyword], "%s%")
                })
                return $custom ? "[%s%]".push(str, "%s%") : str
            },
            each(func) {
                this.forEach(func)
                return this
            }
        }
        Object.entries(e).forEach((e) => {
            Array.prototype[e[0]] = e[1]
        })
        Boolean.prototype.log = log
        /* --- Vue-Router safety mode start --- */
        Object.prototype.log = log
        Object.prototype.array = function () {
            return Object.entries(this)
        }
        /* --- Vue-Router safety mode end --- */
        if (FASTJS_CONFIG.log.fastjsInstallLog)
            console.log(`Fastjs v${FASTJS_CONFIG.version} already install successfully!`)
        if (FASTJS_CONFIG.css.setup)
            new dom("style").html("body{margin: 0;font-family:-apple-system,BlinkMacSystemFont,\"SegoeUI\",Roboto,\"HelveticaNeue\",Arial,sans-serif,\"AppleColorEmoji\",\"SegoeUIEmoji\",\"SegoeUISymbol\",\"NotoColorEmoji\";}*{box-sizing:border-box;}input:focus{outline:none}button:focus{outline:none;}a{text-decoration-line:none;color:unset;}a:hover{text-decoration-line:none;color:unset;}").attr("about", "fastjs-autoinstall-css").push("head")
    },
    random: ($lower, $upper) => {
        if ($upper <= $lower) {
            fastjs.throwCrashError("main.random", "$lower and $upper is not standard")
            return void 0
        }
        if (!js.type($lower, "number") || !js.type($upper, "number")) {
            fastjs.throwCrashError("main.random", "$lower or $upper", "type")
            return void 0
        }
        return Math.floor(Math.random() * ($upper - $lower + 1)) + $lower
    },
    throwSmallError: (e, val) => {
        if (FASTJS_CONFIG.error.output.smallErrorOutput)
            console.warn(`[Fastjs Error] Fastjs.${e}.smallError: ${val}`)
    },
    throwError: (e, val) => {
        if (FASTJS_CONFIG.error.output.errorOutput)
            console.warn(`[Fastjs Error] Fastjs.${e}.error: ${val}`)
    },
    throwSeriousError: (e, val) => {
        if (FASTJS_CONFIG.error.output.seriousErrorOutput)
            console.warn(`[Fastjs Error] Fastjs.${e}.seriousError: ${val}`)
    },
    throwCrashError: (e, val, reason) => {
        if (reason === "type")
            console.error(`Fastjs.${e}.crashError: unknown type given of ${val}`)
        else
            console.error(`Fastjs.${e}.crashError: ${val}`)
    },
    qualityOutput: (e, val) => {
        if (FASTJS_CONFIG.compiler.qualityInspection)
            console.log(`[Fastjs quality inspection] Fastjs.${e}.qualityInspection: ${val}`)
    },
    domAddEnd: ($domadd, e) => {
        e.appendChild($domadd)
    },
    dom: (selecter, el = document) => {
        /*
         * @string selecter
         * @element el
         */

        let st = selecter
        if (st == null) return document
        if (st[0] == "#" ? true : ["body", "html", "head"].search(st) !== false)
            el = el.querySelector(st)
        else el = el.querySelectorAll(st)
        return el
    },
    library: (e, config) => {
        if (e === "function") {
            if (fastjs[config.name] !== undefined && config.global)
                window[config.name] = config.function
        }
        window.js = fastjs
    },
    copy: (data) => {
        var oInput = document.createElement('input')
        oInput.value = data
        document.body.appendChild(oInput)
        oInput.select()
        document.execCommand("Copy")
        oInput.className = 'oInput'
        oInput.style.display = 'none'
        oInput.remove()
    },
    type: (e, ct) => {
        return ct === undefined ? typeof e == "object" ? e.__proto__.at === undefined ? "object" : "array" : typeof e : typeof e == "object" ? e.__proto__.at === undefined ? "object" === ct : "array" === ct : typeof e === ct
    }
}

fastjs.setup()